/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package k3tool.common.filter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Nodes;
import nu.xom.ParsingException;
import nu.xom.ValidityException;
import nu.xom.XPathContext;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

/**
 * Build title from XHTML file or directory.
 *
 * A typical kindle-tools directory will contains an .info.xml file,
 * the first //Title element contains the title of the directory.
 *
 * @author Jeff Huang
 */
public class SimpleTitleBuilder {

    public static final Pattern ARTIFICIAL_ORDER_PATTERN = Pattern.compile("^[0-9]{3}-(.+)$");
    private static final Logger logger = Logger.getLogger(SimpleTitleBuilder.class.getName());

    public String buildTitle(File file) {
        if (file == null) {
            throw new IllegalArgumentException("File should not be null");
        }

        if (!file.exists()) {
            throw new IllegalArgumentException(new FileNotFoundException(file.getAbsolutePath()));
        }

        if (file.isDirectory()) {
            return buildDirectoryTitle(file);
        }

        String lowerCaseFileName = file.getName().toLowerCase();
        if (lowerCaseFileName.endsWith(".htm") || lowerCaseFileName.endsWith(".html") || lowerCaseFileName.endsWith(".xhtml")) {
            try{
                return getTitleFromXHtmlFile(file, "UTF-8");
            }catch(Exception ex){
                return buildTitleFromFileName(file);
            }
        }


        Document doc = null;
        try {
            Builder builder = new Builder(false);
            doc = builder.build(file);
        } catch (IOException ex) {
            logger.log(Level.WARNING, file.getAbsolutePath(), ex);
            return buildTitleFromFileName(file);
        } catch (ParsingException ex) {
            //it is not a valid xml/xhtml file
            return buildTitleFromFileName(file);
        }

        Nodes nodes = doc.query("//title");
        if (nodes.size() == 0) {
            return buildTitleFromFileName(file);
        }

        String title = nodes.get(0).getValue().trim();
        if (title.isEmpty()) {
            return buildTitleFromFileName(file);
        }

        return title;
    }

    public String buildDirectoryTitle(File file) {
        if (!file.isDirectory()) {
            throw new IllegalArgumentException(file.getAbsolutePath() + " is not a directory");
        }
        File infoFile = new File(file, ".info.xml");
        if (!infoFile.exists()) {
            return buildTitleFromName(file.getName());
        }

        Builder builder = new Builder();
        try {
            Document doc = builder.build(infoFile);
            Nodes nodes = doc.query("//Title/text()");
            if (nodes.size() == 0) {
                return buildTitleFromName(file.getName());
            }
            String v = nodes.get(0).getValue();
            if (v == null) {
                return buildTitleFromName(file.getName());
            }
            v = v.trim();
            if (v.isEmpty()) {
                return buildTitleFromName(file.getName());
            }
            return v;
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        } catch (ParsingException ex) {
            throw new RuntimeException(ex);
        }
    }

    public String buildTitleFromName(String name) {
        Matcher matcher = ARTIFICIAL_ORDER_PATTERN.matcher(name);
        if (!matcher.matches()) {
            return name;
        }
        String v = matcher.group(1);
        if (v.isEmpty()) {
            return name;
        }
        return v;
    }

    private String buildTitleFromFileName(File file) {
        String fileName = file.getName();
        int pos = fileName.lastIndexOf(".");
        if (pos == -1) {
            return buildTitleFromName(fileName);
        }

        fileName = fileName.substring(0, pos);
        if (fileName.isEmpty()) {
            return file.getName();
        }

        return buildTitleFromName(fileName);
    }

    String getTitleFromXHtmlFile(final File file, String encoding) throws Exception {
        return (String)XHtmlConstants.processXHtmlDocument(file, encoding, new XHtmlConstants.XHtmlProcessor() {

            @Override
            public Object process(Document doc, XPathContext context) {                
                Nodes titleNodes = doc.query("//html:title/text()", context);
                if (titleNodes.size() > 0) {
                    return titleNodes.get(0).getValue();
                }

                return buildTitleFromName(file.getName());
            }
        });
        
    }
}
